package crypto

import (
	"blockchain/types"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/sha256"
	"math/big"
)

type PublicKey struct {
	Key *ecdsa.PublicKey
}

func (k *PublicKey) ToBytes() []byte {
	return elliptic.MarshalCompressed(k.Key.Curve, k.Key.X, k.Key.Y)
}

func (k *PublicKey) Address() types.Address {
	h := sha256.Sum256(k.ToBytes())
	return types.Address(h[:20])
}

type PrivateKey struct {
	Key *ecdsa.PrivateKey
}

type Signature struct {
	r big.Int
	s big.Int
}

func (s *Signature) Verify(key PublicKey, data []byte) bool {
	return ecdsa.Verify(key.Key, data, &s.r, &s.s)
}

func GeneratePrivateKey() PrivateKey {
	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		panic(err)
	}

	return PrivateKey{Key: key}
}

func (k *PrivateKey) PublicKey() PublicKey {
	return PublicKey{Key: &k.Key.PublicKey}
}

func (k *PrivateKey) Sign(data []byte) (*Signature, error) {
	r, s, err := ecdsa.Sign(rand.Reader, k.Key, data)
	if err != nil {
		return nil, err
	}

	return &Signature{r: *r, s: *s}, nil
}
